package com.edu.demo.aspect;

import cn.hutool.core.bean.BeanUtil;
import com.edu.demo.anno.AutoCustomAnnotation;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;

/**
 * 通过AOP完成对自定义注解下的方法进行自动化缓存
 */
@Slf4j
@Aspect //标记是一个AOP切面
@Component //放到IOC容器管理
public class RedisCachingAspect {

    @Autowired
    private RedisTemplate redisTemplate;

    @Around("@annotation(com.edu.demo.anno.AutoCustomAnnotation)") //可以写全路径
    public Object cacheAroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        //-----------------------------------------获取注解的参数 开始-------------------------------------------------------------
        //获取方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //获取方法对象
        Method method = signature.getMethod();
        //通过方法对象，获取方法上携带的注解
        AutoCustomAnnotation annotation = method.getAnnotation(AutoCustomAnnotation.class);
        //获取自定义注解的参数
        long ttl = annotation.ttl();
        String group = annotation.group();
        //-----------------------------------------获取注解的参数 结束-----------------------------------------------------

        //-----------------------------------------通过现有条件生产一个key 开始-----------------------------------------------------
        String key = getCacheKey(group, signature, joinPoint);
        log.info("唯一Key:{}", key);
        //-----------------------------------------通过现有条件生产一个key 结束-----------------------------------------------------

        //-----------------------------------------判断Redis所有有这个Key 开始-----------------------------------------------------
        if (redisTemplate.hasKey(key)) {
            log.info("执行查询Redis");
            Gson gson = new Gson();
            Object o = gson.fromJson(redisTemplate.opsForValue().get(key).toString(), method.getReturnType());
            log.info("Redis内的数据:{}",o);
            return o;
        }
        //-----------------------------------------判断Redis所有有这个Key 结束-----------------------------------------------------

        //proceed原方的法返回值
        Object proceed = joinPoint.proceed();
        log.info("数据库内的数据:{}",proceed);
        //-----------------------------------------在Redis内缓存数据 开始-----------------------------------------------------
        if (ttl > 0) {
            redisTemplate.opsForValue().set(key, proceed, ttl, TimeUnit.MILLISECONDS);
        } else {
            redisTemplate.opsForValue().set(key, proceed);
        }
        log.info("执行数据库");
        //-----------------------------------------在Redis内缓存数据 结束-----------------------------------------------------

        return proceed;
    }

    //用来生成一个key
    public String getCacheKey(String group, MethodSignature methodSignature, JoinPoint joinPoint) {
        //分组拼接上参数
        String key = group + ":" + methodSignature.getName() + ":" + Arrays.toString(joinPoint.getArgs());
        return key;
    }

}
